#include <stdlib.h>
#include <stdbool.h>

#include <assert.h>

#include "queue.h"

struct queue {
	struct node * head;
	struct node * tail;
};

struct node {
	struct node * next;
	void * payload;
};
	
struct queue * queue_init()
{
	struct queue * q = NULL;
	if (!(q = malloc(sizeof(*q))))
		goto err;

	q->head = NULL;
	q->tail = NULL;
err:
	return q;
}

void queue_fini(struct queue * q)
{
	if (!q)
		return;
	while(q->head)
		queue_remove(q, NULL);
	free(q);
	q = NULL;
}

int queue_add(struct queue * q, void * p)
{
	int ret = -1;
	struct node * node = NULL;
	if (!(node = malloc(sizeof(*node))))
		goto err;
	node->next = NULL;
	node->payload = p;
	if (q->tail) {
		q->tail->next = node;
		q->tail = node;
	} else {
		q->head = node;
		q->tail = node;
	}
	
	ret = 0;
err:
	return ret;
}

int queue_peek(struct queue *q, void ** p)
{
	int ret = -1;
	if ((!q) || (!q->head) || (!p))
		goto err;
	*p = q->head->payload;
	ret = 0;
err:
	return ret;
}

int queue_remove(struct queue * q, void ** p)
{
	int ret = -1;
	struct node * node;
	if ((!q) || (!q->head))
		goto err;
	node = q->head;
	q->head = node->next;
	if (!q->head)
		q->tail = NULL;
	if (NULL != p) { 
		*p = node->payload;
	}
	free(node);
	ret = 0;
err:
	return ret;
}

bool queue_is_empty(struct queue * q) {
	if (!q)
		return true;
	return (q->head == NULL);
}
